package com.quanyue.music.user.controller;

import cn.binarywang.wx.miniapp.api.WxMaMsgService;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
import com.quanyue.auto.cache.CacheService;
import com.quanyue.auto.miniapp.support.MiniAppContext;
import com.quanyue.auto.util.AssertUtils;
import com.quanyue.auto.util.KeyGenerator;
import com.quanyue.auto.util.ServiceResult;
import com.quanyue.auto.util.StringUtils;
import com.quanyue.auto.web.Principal;
import com.quanyue.auto.web.RequestContext;
import com.quanyue.auto.web.Scope;
import com.quanyue.auto.web.WebUtils;
import com.quanyue.music.domain.constant.CacheConstants;
import com.quanyue.music.domain.constant.UserAgent;
import com.quanyue.music.domain.constant.UserRole;
import com.quanyue.music.domain.entity.FormId;
import com.quanyue.music.domain.entity.IsTest;
import com.quanyue.music.domain.entity.ShareRecord;
import com.quanyue.music.domain.entity.User;
import com.quanyue.music.system.mapper.IpBlockMapper;
import com.quanyue.music.system.mapper.IsTestMapper;
import com.quanyue.music.system.service.DomainService;
import com.quanyue.music.template.service.TemplateService;
import com.quanyue.music.user.mapper.ShareRecordMapper;
import com.quanyue.music.user.mapper.UserMapper;
import com.quanyue.music.user.service.UserService;
import com.quanyue.music.user.type.MiniAppRequest;
import com.quanyue.music.user.type.MiniCode;
import com.quanyue.music.user.type.UserDetail;
import com.shzisg.mybatis.mapper.page.Page;
import com.shzisg.mybatis.mapper.page.PageRequest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import me.chanjar.weixin.common.exception.WxErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.quanyue.music.domain.constant.TemplateId.INVITE_RESULT;

@Api(tags = "用户")
@Scope(role = UserRole.USER)
@RestController
@RequestMapping("/api")
public class UserController {

    @Autowired
    private WxMaService wxMaService;
    @Autowired
    private UserService userService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private IsTestMapper isTestMapper;
    @Autowired
    private IpBlockMapper ipBlockMapper;
    @Autowired
    private ShareRecordMapper shareRecordMapper;
    @Autowired
    private DomainService domainService;
    @Autowired
    private TemplateService templateService;
    @Autowired
    private WxMaMsgService wxMaMsgService;

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @ApiOperation(value = "测试登录")
    @GetMapping(value = "/user/login", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public void testLogin(@RequestParam("username") String username,
                          @ApiIgnore HttpServletResponse response,
                          @ApiIgnore RequestContext context) throws IOException {
        User user = userService.findByName(username);
        context.updatePricipal(new Principal(user.getId(), 10100, UserRole.USER, UserAgent.BROWSER));
        response.sendRedirect("/home");
    }

    @ApiOperation(value = "小程序测试登录")
    @GetMapping(value = "/user/miniapp/test/login", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <Map <String, Object>> miniAppTestLogin(@RequestParam("username") String username, HttpServletRequest request) throws Exception {
        User user = userService.findByName(username);
        Principal principal = new Principal(user.getId(), 10100, UserRole.USER, UserAgent.MINI_APP);
        String key = KeyGenerator.uuid();
        cacheService.put(CacheConstants.SESSION_CACHE.name(), key, principal);
        ShareRecord record = shareRecordMapper.findByUserId(user.getId());
        IsTest isTest = isTestMapper.findAll().get(0);
        Map <String, Object> values = new HashMap <>();
        values.put(key, "test");
        values.put("needUserInfo", false);
        values.put("userId", user.getId());
        values.put("insideUser", user.getInsideUser());
        values.put("email", StringUtils.isBlank(user.getEmail()) ? true : false);
        values.put("isTest", isTest.getIstest());
        values.put("isThemes", isTest.getIsthemes());
        log.info(" 用户IP: {}", WebUtils.getClientIp(request));
        values.put("userIp", userService.getAddressByIP(WebUtils.getClientIp(request)));
        if (record != null) values.put("validCount", record.getValidCount());
        return ServiceResult.success(values);
    }

    @ApiOperation(value = "小程序登录")
    @Transactional(rollbackFor = Exception.class)
    @PostMapping(value = "/user/miniapp/login", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <Map <String, Object>> miniAppLogin(@RequestBody MiniCode code, HttpServletRequest request) throws Exception {
        String domain = "https://" + request.getHeader("host");
        Integer merchantNo = domainService.findMerchantNoByDomain(domain);
        AssertUtils.notNull(merchantNo, "商户不存在");
        MiniAppContext.setMerchantNo(merchantNo);
        WxMaJscode2SessionResult result = wxMaService.getUserService().getSessionInfo(code.getCode());
        User user = userService.findByOpenId(result.getOpenid());
        Principal principal = new Principal();
        principal.setMerchantNo(merchantNo);
        principal.setRole(UserRole.USER);
        principal.setAgent(UserAgent.MINI_APP);
        if (user != null) {
            principal.setId(user.getId());
            BigInteger initNum = user.getLoginNum();
            if (initNum == null) initNum = BigInteger.ONE;
            user.setLoginNum(initNum.add(BigInteger.ONE));
            userMapper.updateSelective(user);
        }
        String key = KeyGenerator.uuid();
        cacheService.put(CacheConstants.SESSION_CACHE.name(), key, principal);
        IsTest isTest = isTestMapper.findAll().get(0);
        Boolean ipBlock = ipBlockMapper.findAll().get(0).getIsOpen();
        // result
        Map <String, Object> values = new ConcurrentHashMap <>();
        values.put(key, result.getSessionKey() + result.getOpenid());
        values.put("needUserInfo", user == null);
        if (user != null) {
            values.put("userId", user.getId());
            values.put("insideUser", user.getInsideUser());
            values.put("email", user.getEmail() == null ? true : false);
        }
        values.put("isTest", isTest.getIstest());
        values.put("isThemes", isTest.getIsthemes());
        log.info("用户IP地址: {}", WebUtils.getClientIp(request));
        if (ipBlock) {
            values.put("userIp", userService.getAddressByIP(WebUtils.getClientIp(request)));
        } else {
            values.put("userIp", true);
        }
        log.info("Login返回值：{}", values);
        return ServiceResult.success(values);
    }

    @ApiOperation(value = "小程序用户初始化")
    @Transactional
    @PostMapping(value = "/user/miniapp/register", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <Boolean> miniAppRegister(@RequestBody MiniAppRequest request, Principal principal) throws Exception {
        MiniAppContext.setMerchantNo(principal.getMerchantNo());
        request.setSessionKey(request.getSessionKey().substring(0, 23));
        WxMaUserInfo userInfo = wxMaService.getUserService()
                .getUserInfo(request.getSessionKey(), request.getEncryptedData(), request.getIvStr());
        if (userInfo != null) {
            User user = userService.findByOpenId(userInfo.getOpenId());
            if (user != null) {
                return ServiceResult.SUCCESS;
            }
            user = new User();
            user.setNickName(userInfo.getNickName());
            user.setOpenId(userInfo.getOpenId());
            user.setHeadImage(userInfo.getAvatarUrl());
            user.setSex(Integer.valueOf(userInfo.getGender()));
            user.setPhone("");
            user.setDelFlag(false);
            user.setInsideUser(false);
            user.setFlowType(false);
            user.setLoginNum(BigInteger.ONE);
            user.setQyCode(request.getQrCode());
            user.setEmail(request.getEmail());
            user = userService.add(user);
            principal.setId(user.getId());
        }
        if (StringUtils.isNotBlank(request.getIssueUser())) {
            ShareRecord record = shareRecordMapper.findByUserId(request.getIssueUser());
            if (record != null) {
                record.setValidCount(record.getValidCount() + 1);
                shareRecordMapper.update(record);
            } else {
                ShareRecord shareRecord = new ShareRecord();
                shareRecord.setValidCount(1);
                shareRecord.setIsConvert(false);
                shareRecord.setIssueUser(request.getIssueUser());
                shareRecordMapper.insert(shareRecord);
            }
            // 消息通知
            List <WxMaTemplateMessage.Data> dataList = new ArrayList <>();
            // 封装模板消息参数
            User user = userMapper.findOne(request.getIssueUser());
            List <FormId> formIds = templateService.getFormId(user.getId());
            if (!formIds.isEmpty()) {
                WxMaTemplateMessage message = WxMaTemplateMessage.newBuilder().build();
                message.setToUser(user.getOpenId());
                message.setTemplateId(INVITE_RESULT.getTemplateId());
                message.setPage(INVITE_RESULT.getUrl());
                message.setFormId(formIds.get(0).getFormId());
                templateService.delOne(formIds.get(0).getId());
                if (message != null) {
                    String content = "哇！恭喜你成功安利1位好友入伙歪果，加把油，再邀请？个朋友，就能get一个月免费VIP";
                    dataList.add(new WxMaTemplateMessage.Data("keyword1", "成功"));
                    dataList.add(new WxMaTemplateMessage.Data("keyword2", "成功邀请三个好友就能获得奖励哦"));
                    dataList.add(new WxMaTemplateMessage.Data("keyword3", record.getValidCount().toString()));
                    dataList.add(new WxMaTemplateMessage.Data("keyword4", LocalDateTime.now().toString()));
                    dataList.add(new WxMaTemplateMessage.Data("keyword5", content));
                    try {
                        message.setData(dataList);
                        MiniAppContext.setMerchantNo(10100);
                        wxMaMsgService.sendTemplateMsg(message);
                    } catch (WxErrorException e) {
                        throw new RuntimeException(e);
                    } catch (NullPointerException e) {
                        log.error("form_id: ", message.getFormId());
                    }
                }
            }
        }
        return ServiceResult.SUCCESS;
    }

    @ApiOperation(value = "用户列表")
    @Scope(role = UserRole.MANAGER)
    @PostMapping(value = "/users", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <Page <UserDetail>> users(@RequestBody PageRequest request) {
        return ServiceResult.success(userService.findUsers(request));
    }

    @ApiOperation(value = "更新用户邮箱信息")
    @GetMapping(value = "/users", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <Boolean> users(@RequestParam("email") String email,
                                         @ApiIgnore Principal principal) {
        userService.updateEmail(email, principal.getId());
        return ServiceResult.SUCCESS;
    }

    @ApiOperation(value = "用户列表导出Excel")
    @Scope(role = UserRole.MANAGER)
    @GetMapping(value = "/user/excel", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <String> userExcel() {
        return ServiceResult.success(userService.excelUser());
    }

    @ApiOperation(value = "用户每日收听时长导出Excel")
    @Scope(role = UserRole.MANAGER)
    @GetMapping(value = "/user/excel/everyday", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <String> userExcelEveryday(@RequestParam("date") String date) {
        return ServiceResult.success(userService.excelUserEveryday(date));
    }

    @ApiOperation(value = "取消内部员工权限")
    @Scope(role = UserRole.MANAGER)
    @GetMapping(value = "/delete/inside/user", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <Boolean> updateUser(@RequestParam("userId") String userId) {
        User user = userMapper.findOne(userId);
        AssertUtils.notNull(user, "没有该会员信息");
        user.setModifyTime(LocalDateTime.now());
        user.setInsideUser(false);
        userMapper.updateSelective(user);
        return ServiceResult.SUCCESS;
    }

    @ApiOperation(value = "修改流量模式")
    @GetMapping(value = "/update/flow/type", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ServiceResult <Boolean> updateFlowType(@RequestParam("isOpen") String isOpen, Principal principal) {
        User user = userMapper.findOne(principal.getId());
        if (user == null) return ServiceResult.success(false);
        user.setFlowType(Boolean.valueOf(isOpen));
        userMapper.updateSelective(user);
        return ServiceResult.SUCCESS;
    }
}
